﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using Db4objects.Db4o;
using Layers;

using NLog;

namespace HoldemGame
{
    using HoldemHand;

    public static class HoldemStage
    {
        public const int Start = 0;
        public const int PreFlop = 1;
        public const int PostFlop = 2;
        public const int PostTurn = 3;
        public const int PostRiver = 4;
        public const int Showdown = 5;

        public static string NameOf(int stage)
        {
            return _stageNames[stage];
        }

        private static string[] _stageNames = new string[]{
            "Start","PreFlop","PostFlop","PostTurn","PostRiver","Showdown"
        };
    }

    public class BrainAction
    {
        public const int FOLD = HoldemActionID.FOLD;
        public const int CALL = HoldemActionID.CALL;
        public const int RAISE = HoldemActionID.RAISE;
        public const int BLIND = HoldemActionID.BLIND;

        public int ID { get; set; }

        public BrainAction(int id){ID=id;}

        public static BrainAction Fold = new BrainAction(FOLD);
        public static BrainAction Call = new BrainAction(CALL);
        public static BrainAction Raise = new BrainAction(RAISE);
        public static BrainAction Blind = new BrainAction(BLIND);

        public override string ToString()
        {
            return HoldemActionID.ToString(ID);
        }

        public BrainAction Clone()
        {
            return new BrainAction(this.ID);
        }
    }

    public interface IBrains
    {
        string ID{get;}
        BrainAction Think(IGameState game, GamePlayer me);
    }

    public interface IGame 
    {
        IGameState State { get; }
        IGameServer Server { get; }
        GameOptions GameOptions { get; }
    }

    public interface IGameBase
    {
        string GameID { get; }
        int Step { get; }
        int Stage { get; }
        GameOptions GameOptions { get; }
    }

    public interface IGameState : IGameBase
    {

        double GetBlindAmount(GamePlayer p);
        double GetRaiseAmount(GamePlayer p);
        double GetCallAmount(GamePlayer p);
        double GetBet(GamePlayer p);

        GamePlayers Players { get; }
        GamePlayer CurrentPlayer { get; }
        GameTable Table { get; }
        GameRoom Room { get; }

        double Pot { get; set;}

        bool IsFinalStage();


        bool CanRaise(GamePlayer p);
        int RaiseCount { get; }

        //void SetMe(GamePlayer me);

        Odds CalcOdds(GamePlayer me);
        GameOptions GameOptions { get; }

        event EventHandler GameStateChanged;
    }

    public interface IGameServer:IGameBase
    {
        void NewGame();
        void Final();
        void PreFlop();
        void PostFlop(CardSet cset);
        void PostTurn(CardSet cset);
        void PostRiver(CardSet cset);
        void SetFirst(GamePlayer p);
        void SetCurrent(GamePlayer p);
        
        void PocketCards(GamePlayer p, CardSet cset);
        void BoardCards(CardSet cset);

        void ShowCards(GamePlayer p);
        
        void Blind();
        void Raise();
        void Call();
        void Fold();
        void Win(GamePlayer p, double amount);

        void SwitchFirst();

        bool IsWantBreak { get; }
        bool NextStep();
    }

    public interface IHoldemActionConsumer
    {
        void Do(HoldemAction action);
    }

    
    public abstract class GameBase : IGame
    {
        private IGameServer _server;
        private IGameState _state;

        public IGameServer Server { get{return _server;} set{_server=value; ServerChanged();} }
        public IGameState State { get{return _state;} set{_state=value;StateChanged();} }

        public GameOptions GameOptions { get; set; }

        public GameBase(IGameServer server, IGameState state, GameOptions opts)
        {
            Server = server;
            State = state;
            GameOptions = opts;
        }

        public GameBase()
        {
        }

        public void ConnectGame(IGame game)
        {
            this.GameOptions = game.GameOptions;
            this.State = game.State;
            this.Server = game.Server;


        }

        protected virtual void ServerChanged()
        {
        }

        protected virtual void StateChanged()
        {
        }
    }

    public class GameProxy : GameBase, IGameState, IGameServer
    {
        public IGame Game;

        public IHoldemActionConsumer Consumer;

        private List<HoldemAction> Queue = new List<HoldemAction>();

        public GameProxy(IGame game, IHoldemActionConsumer consumer) : base(game.Server, game.State, game.GameOptions)
        {
            this.Game = game;
            this.GameOptions = game.GameOptions;
            this.Consumer = consumer;
        }

        public void Enqueue(HoldemAction ha)
        {
            Queue.Add(ha);
            ConsumeAll();
        }

        public void ConsumeAll()
        {
            while (Queue.Count > 0)
            {
                HoldemAction ha = Queue[0];
                Queue.RemoveAt(0);
                Consumer.Do(ha);
            }

        }

        #region IGameState

        public int Step { get { return State.Step; } }
        public double Pot { get { return State.Pot; } set { State.Pot=value;} }
        public GameTable Table { get { return State.Table; } }
        public int Stage { get { return State.Stage; } }
        public string GameID { get { return State.GameID; } }
        public GamePlayers Players { get { return State.Players; } }
        public bool IsFinalStage() { return State.IsFinalStage(); }
        public int RaiseCount { get { return State.RaiseCount; } }
        public bool CanRaise(GamePlayer p) { return State.CanRaise(p); }
        public Odds CalcOdds(GamePlayer me) { return State.CalcOdds(me); }
        public double GetBlindAmount(GamePlayer p) { return State.GetBlindAmount(p); }
        public double GetCallAmount(GamePlayer p) { return State.GetCallAmount(p); }
        public double GetBet(GamePlayer p) { return State.GetBet(p); }
        public double GetRaiseAmount(GamePlayer p) { return State.GetRaiseAmount(p); }
        public GameRoom Room { get { return State.Room; } }
    
//        public void SetMe(GamePlayer me) { State.SetMe(me); } // TODO: Exclude

        public GamePlayer CurrentPlayer { get { return State.CurrentPlayer; } }

        public event EventHandler GameStateChanged
        {
            add { State.GameStateChanged += value; }
            remove { State.GameStateChanged -= value; }
        }
        #endregion

        #region IGameServer Members

        public void NewGame()
        {
            HoldemAction sd = StageAction.Create(HoldemActionID.START, Server);
            Enqueue(sd);
        }

        public void Final()
        {
            // have winners here
            HoldemAction sd = StageAction.Create(HoldemActionID.FINAL, Server);
            Enqueue(sd);
        }

        public void PreFlop()
        {

            // switch to preflop
            HoldemAction pfa = StageAction.Create(HoldemActionID.PREFLOP, Server);
            Enqueue(pfa);
        }

        public void PostFlop(CardSet cset)
        {
            HoldemAction a = BoardCardsAction.Create(HoldemActionID.FLOP, Server, cset);
            Enqueue(a);
        }

        public void PostTurn(CardSet cset)
        {
            HoldemAction a = BoardCardsAction.Create(HoldemActionID.TURN, Server, cset);
            Enqueue(a);
        }
        //+
        public void PostRiver(CardSet cset)
        {
            HoldemAction a = BoardCardsAction.Create(HoldemActionID.RIVER, Server, cset);
            Enqueue(a);
        }

        public void PocketCards(GamePlayer p, CardSet cset)
        {
            PocketCardsAction a = PocketCardsAction.Create(Server, p, cset);
            Enqueue(a);
        }

        public void BoardCards(CardSet cset)
        {
            HoldemAction a = BoardCardsAction.Create(HoldemActionID.BOARDCARDS, Server, cset);
            Enqueue(a);
        }

        public void ShowCards(GamePlayer p)
        {
            // open cards to all players
            HoldemAction oc = PlayerStateAction.Create(HoldemActionID.SHOW, Server, p);
            Enqueue(oc);
        }


        public void Win(GamePlayer p, double amount)
        {
            HoldemAction a = WinAction.Create(HoldemActionID.WIN, Server, p, amount);
            Enqueue(a);
        }

        public void Blind()
        {
            HoldemAction action = BlindAction.Create(HoldemActionID.BLIND, Server, State.CurrentPlayer, State.GetBlindAmount(Players.Current));
            Enqueue(action);
        }

        //+
        public void Raise()
        {
            HoldemAction action = RaiseAction.Create(HoldemActionID.RAISE, Server, State.Players.Current, State.GetRaiseAmount(Players.Current));
            Enqueue(action);
        }

        //+
        public void Call()
        {
            HoldemAction action = CallAction.Create(HoldemActionID.CALL, Server, State.Players.Current, State.GetCallAmount(Players.Current));
            Enqueue(action);
        }

        //+
        public void Fold()
        {
            HoldemAction action = FoldAction.Create(Server, State.Players.Current);
            Enqueue(action);
        }

        //+
        public void SetFirst(GamePlayer p)
        {
            HoldemAction a = PlayerPositionAction.Create(HoldemActionID.FIRST, Server, p);
            Enqueue(a);
        }

        //+
        public void SetCurrent(GamePlayer p)
        {
            HoldemAction a = PlayerPositionAction.Create(HoldemActionID.CURRENT, Server, p);
            Enqueue(a);
        }

        public void SwitchFirst()
        {
            HoldemAction a = PlayerPositionAction.Create(HoldemActionID.SWITCHFIRST, Server, Players.Current);
            Enqueue(a);

        } 

        #endregion

        

        // TODO: Move to IGameDebug
        public bool IsWantBreak { get { return Server.IsWantBreak; } }
        public bool NextStep() { return Server.NextStep(); }
    }

    public class GameOptions : GameObject
    {
        public static int ShowAllCards = 0x01;
        private BitSet _options = new BitSet(0);

        public bool IsShowAllCards
        {
            get { return _options.Get(GameOptions.ShowAllCards); }
            set{_options.Set(GameOptions.ShowAllCards, value); Changed();}
        }

        public GameOptions(Game game):base(game)
        {

        }

        private void Changed()
        {
            Game.StateChanged();
        }
    }

    /// <summary>
    /// Represents single game
    /// Defines players, who is the dealer(button), who is Big or Small Blind.
    /// Defines game rules as well
    /// </summary>
    public class Game : GameBase, IGameServer, IGameState, IHoldemActionConsumer
    {
        #region Fields
        
        // persistent
        private int _stage;
        private double _pot;
        private string _ID;
        private double _maxStake;
        private int _step;
        private double _smallBlindAmount = 1;
        private double _bigBlindAmount = 2;

        private Dealer _dealer;

        private GamePlayers _players;
        private GameTable _table;

        // transient
        [Transient()]
        private MyLogger _log = MyLogger.Default;
        private EventHandler<HoldemActionEventArgs> _postAction;
        private EventHandler _stateChanged;

        private IGameServer _proxy;

        private HoldemActionHistory _history;

        private GamePlayer _me = null;

        private int MaxRaiseCount = 3;

        private int _raiseCount = 0;

        private bool _wantBreak = false;

        private OddsCalc _oddsCalc;

        private GameRoom _room;
        #endregion

        public bool IsWantBreak { get { return _wantBreak; } }

        public GameRoom Room { get { return _room; } set { _room = value; } }

        public double SmallBlindAmount { get { return _smallBlindAmount; } }
        
        public double BigBlindAmount { get { return _bigBlindAmount; } }

        public GamePlayers Players { get { return _players; } }
        
        public GameTable Table 
        { 
            get 
            {
                return _table; 
            } 
        }

        public IGameServer Proxy { get { return _proxy; } }

        //public GamePlayer Me { get { return _me; } set { SetMe(value); } }

        public int Step{get{return _step;}}

        public int Stage 
        {
            get { return _stage; } 
            set { 
                int old = _stage;
                _stage=value;
                StageChanged(old);
            }
        }

        public double Pot { get { return _pot; } set { _pot = value; StateChanged(); } }

        public Dealer Dealer { get { return _dealer; } }

        public event EventHandler<HoldemActionEventArgs> PostAction
        {
            add { _postAction +=value; }
            remove { _postAction -=value;}
        }

        public event EventHandler GameStateChanged
        {
            add { _stateChanged+=value; }
            remove { _stateChanged-=value; }
        }

        public Game() 
        {
            Server = this;
            State = this;
            GameOptions  = new GameOptions(this);

            _players = new GamePlayers(this);
            _stage = HoldemStage.Start;
            _dealer = new Dealer();
             _history = new HoldemActionHistory(this);

            _oddsCalc = new OddsVsRandomOneCalc();
            //_oddsCalc = new OddsVsEstCardsCalc();
            
            _proxy = new GameProxy(this, this);
            
            _table = new GameTable(this);
            _players.Listen(_table.Seats);
        }

        public Game(string id, GameRoom room) : this()
        {
            _ID=id;
            Room = room;
        }

        public HoldemActionHistory History { get { return _history; } set { _history=value;} }

        public GamePlayer CreatePlayer(string id, int position, double stake)
        {
            GamePlayer player = new GamePlayer();
            player.Game = this;
            player.Stake = stake;
            player.ID = id;
            return player;
        }

        public void Break()
        {
            _wantBreak = true;
        }

        public uint EvaluateHand(GamePlayer p)
        {
            CardSet cset = CardSet.Merge(p.PocketCards, Table.BoardCards());
            uint handValue = Hand.Evaluate(cset.ToString());
//            _log.Info("Evaluate hand {0} of {1} = {2} {3}", cset, p.ID, handValue, Hand.DescriptionFromHandValue(handValue));
            p.HandValue = handValue;
            return handValue;
        }

        public bool IsBlind(GamePlayer p)
        {
            return p.Position <= 1 && _step <= 1; ;
        }


        public double GetBet(GamePlayer p)
        {
            switch (Stage)
            {
                case HoldemStage.PreFlop: return BigBlindAmount;
                default: return 2 * BigBlindAmount;
            }
        }

        public double GetRaiseAmount(GamePlayer p)
        {
            return _maxStake + GetBet(p) - p.Stake;
        }

        public double GetCallAmount(GamePlayer p)
        {
            return _maxStake - p.Stake;
        }

        public double GetBlindAmount(GamePlayer p)
        {
            if (Stage == HoldemStage.PreFlop)
            {
                if (p.Position == 0)
                    return SmallBlindAmount;
                if (p.Position == 1)
                    return BigBlindAmount;
            }
            return 0;
        }

        
        /*public void SetMe(GamePlayer me)
        {
            if (_me != null)
                _me.ForceShow = false;
            _me=me;
            if(null!=_me)
                _me.ForceShow = true;
            CalcOdds(_me);
            StateChanged();
        }*/

        public bool IsRoundFinished()
        {
            if (Stage == HoldemStage.Start)
                return true;

            if (Players.ActiveCount <= 1)
                return true; // have nobody else
            
            if(_maxStake>0)
                foreach (GamePlayer p in Players.Active)
                {
                    if (p.Stake != _maxStake)
                        return false; // somebody didn't tell us his word
                }

            
            if (Players.Current.CallCount==0 && CanRaise(Players.Current))
                return false;    // we still can raise and didn't called

            return true;
        }

        public bool CanRaise(GamePlayer p)
        {
            return _raiseCount < 3;//p.RaiseCount<MaxRaiseCount;
        }

        public bool CanCall(GamePlayer p)
        {
            return true;
        }

        public bool HasWinner()
        {
            if (!IsRoundFinished())
                return false;
            return Players.ActiveCount <= 1;
        }

        public bool IsFinalStage()
        {
            return _stage == HoldemStage.Showdown;
        }

        public bool IsActionReady
        {
            get { return Players.Current.IsActionReady; }
        }

        public void Think()
        {
            if (IsActionReady)
                throw new InvalidOperationException("Player has already thought");

            this.Players.Current.Think();


        }

        public void Act()
        {
            if (!IsActionReady)
                throw new InvalidOperationException("No action ready");

            GamePlayer current = Players.Current;

            if (!current.IsManual)
            {
                switch (current.BrainAction.ID)
                {
                        case BrainAction.CALL: _proxy.Call(); break;
                        case BrainAction.RAISE: _proxy.Raise(); break;
                        case BrainAction.FOLD: _proxy.Fold(); break;
                        default: throw new InvalidOperationException();
                }
            }
            else
            {
                Break();
            }
        }

        public GamePlayer CurrentPlayer
        {
            get { return Players.Current;  }
        }

        public bool NextStep()
        {
            _wantBreak = false;

            if (IsFinalStage())
                return false;

            bool fin = IsRoundFinished();
            if(!fin)
            {
                if (!Players.Current.IsActive)
                {
                    throw new InvalidOperationException();
                }
                else
                    if (!IsActionReady)
                        CurrentPlayer.Think();
                    else
                        Act();
                return true;
            }
            else if (HasWinner())
            {
                Showdown();
                return false;
            }else
                if(Stage==HoldemStage.Start)
                {
                    Shuffle();
                    _proxy.SetFirst(Players.First);
                    _proxy.PreFlop();
                    _proxy.Blind();
                    _proxy.Blind();
                    return true;
                }else if(Stage==HoldemStage.PreFlop)
                {
                    _proxy.PostFlop(Table.FlopCards());
                    return true;
                }else if(Stage==HoldemStage.PostFlop)
                {
                    _proxy.PostTurn(Table.TurnCards());
                    return true;
                }else if(Stage==HoldemStage.PostTurn)
                {
                    _proxy.PostRiver(Table.RiverCards());
                    return true;
                }else if(Stage==HoldemStage.PostRiver)
                {
                    Showdown();
                    return false;
                }
            return false;
        }


        //+
        public void Shuffle()
        {
            //TODO::SUFFLE
            CardSet all = new CardSet(2*Players.Count + 5);
            Dealer.Shuffle(all, 0, all.Count - 1);
            Table.BoardCards().CopyFrom(0, all, 0, 5);
            int i=0;
            foreach (GamePlayer p in Players)
            {
                _proxy.PocketCards(p,all.GetCardSet(5+2*i,2,false));
                i++;
            }
            /*Dealer.Shuffle(Table.Cards, 0, Table.Cards.Count-1);
            // give cards to players
            for(int i=0;i<Players.Count;i++)
                _proxy.PocketCards(Players[i], Table.PocketCards(i).Clone());
        */}

        //+

        //+
        public void SwitchFirst()
        {
            Players.First = Players.Seek(Players.First, 1, false);
            _proxy.SetFirst(Players.First);
            StateChanged();
        }
        //+
      
        public void NewRound()
        {
            foreach (GamePlayer p in Players)
                p.NewRound();

            _maxStake = 0;
            _raiseCount = 0;
            GamePlayer curr = Players.First;
            if (!curr.IsActive)
                curr = Players.Seek(curr, 1, true);

            SetCurrent(curr);

            //CalcOdds(Players.Current);

            StateChanged();
        }
        
        //+
        
        //+
        //+
        

        //+1
        public void PocketCards(GamePlayer p, CardSet cset)
        {
            p.PocketCards.CopyFrom(0, cset); // TODO: shit could happen for small cset
            //EvaluateHand(p);
            p.OnPocketCards(p);

            StateChanged();
        }

        public void BoardCards(CardSet cset)
        {
            Table.BoardCards().CopyFrom(0, cset);
            NotifyBoardCards();
            StateChanged();
        }

        private void NotifyBoardCards()
        {
            foreach (GamePlayer p in Players)
                p.OnBoardCards();
        }


        public void ShowCards(GamePlayer p)
        {
            p.IsShown = true;
            StateChanged();
        }

        public int RaiseCount { get { return _raiseCount; } }
        //+1
        public void NewGame()
        {
            Stage = HoldemStage.Start;
            _step = 0;
            _raiseCount = 0;
            Pot = 0;

            Table.ResetCards();

            //Players.First = Players[0];
            foreach (GamePlayer p in Players)
            {
                p.NewGame();
            }

            Players.Current = Players.First;

            _history.Clear();

            StateChanged();
        }

        public void Showdown()
        {
            // show cards of all still hidden players
            foreach (GamePlayer p in Players.Hidden)
            {
                _proxy.PocketCards(p, p.PocketCards);

                _proxy.ShowCards(p);
                EvaluateHand(p);
            }
            _proxy.Final();
        }

        //+1
        public void Final()
        {
            Stage = HoldemStage.Showdown;

//            CalcOdds(null);

            // here we make winner
            List<GamePlayer> winners = new List<GamePlayer>();
            
            uint maxHandValue = 0;
            foreach(GamePlayer p in Players.Active)
            {
                if (p.HandValue > maxHandValue)
                    maxHandValue = p.HandValue;
            }

            foreach (GamePlayer p in Players.Active)
            {
                if(p.HandValue == maxHandValue)
                {
                    winners.Add(p);
                }
            }

            foreach (GamePlayer p in winners)
            {
                _proxy.Win(p, Pot / winners.Count);

            }
            StateChanged();
            //CleanPot();
        }

        //+1
        public void PreFlop()
        {
            Stage = HoldemStage.PreFlop;
            NewRound();
            StateChanged();
        }

        //+1
        public void PostFlop( CardSet flop)
        {
//            _log.Info("To PostFlop");
            Table.FlopCards().CopyFrom(flop);
            Stage = HoldemStage.PostFlop;
            NewRound();
            StateChanged();
        }

        //+1
        public void PostTurn(CardSet turn)
        {
//            _log.Info("To PostTurn");
            Table.TurnCards().CopyFrom(turn);
            Stage = HoldemStage.PostTurn;
            NewRound();
            StateChanged();
        }

        //+1
        public void PostRiver(CardSet river)
        {
//            _log.Info("To PostRiver");
            Table.RiverCards().CopyFrom(river);
            Stage = HoldemStage.PostRiver;
            NewRound();
            StateChanged();
        }

        //+1
        public Odds CalcOdds(GamePlayer me)
        {
            if (Stage == HoldemStage.Start)
                return Odds.Invalid;

            if (null != me)
                _oddsCalc.CalcOdds(this, me);
            else
            {
                foreach (GamePlayer p in Players.Active)
                {
                    _oddsCalc.CalcOdds(this, p);
                }
            }

            StateChanged();
            return me!=null? me.Odds:null;
         }

        //+

        internal void NotifyBrainAction(GamePlayer current, BrainAction a)
        {
            foreach (GamePlayer p in Players)
            {
                p.OnAction(current, a);
            }
        }

        public void Fold()
        {
            VerifyAction();

            Players.Current.BrainAction = BrainAction.Fold;

            NotifyBrainAction(Players.Current, Players.Current.BrainAction);

            Players.Current.BrainAction = null;

            SwitchPlayer();
            StateChanged();
        }

        public void Raise()
        {
            VerifyAction();
            Players.Current.BrainAction = BrainAction.Raise;

            Bet(Players.Current, GetRaiseAmount(Players.Current));

            NotifyBrainAction(Players.Current, Players.Current.BrainAction);
            Players.Current.BrainAction = null;

            _raiseCount++;
            SwitchPlayer();
            StateChanged();
        }

        private void VerifyAction()
        {
            if (!Players.Current.IsActive)
                throw new InvalidOperationException("Player "+Players.Current+" Is Folded but asked to act");
        }
        public void Call()
        {
            VerifyAction();
            
            Players.Current.BrainAction = BrainAction.Call;


            Bet(Players.Current, GetCallAmount(Players.Current));

            NotifyBrainAction(Players.Current, Players.Current.BrainAction);
            Players.Current.BrainAction = null;

            SwitchPlayer();
            StateChanged();
        }

        public void Blind()
        {
            Players.Current.BrainAction = BrainAction.Blind;

            Bet(Players.Current, GetBlindAmount(Players.Current));
            
            NotifyBrainAction(Players.Current, Players.Current.BrainAction);
            
            Players.Current.BrainAction = null;

            SwitchPlayer();
            StateChanged();
        }

        protected virtual void Bet(GamePlayer p, double amount)
        {
            p.Stake+=amount;
            p.Bank-=amount;
            Pot+=amount;
            _maxStake=p.Stake;
        }

        public void Win(GamePlayer p, double amount)
        {
            p.Bank+=amount;
            p.IsWinner = true;
            //Pot-=amount;
        }

        internal void SwitchPlayer()
        {
            Players.SwitchNext();
            _proxy.SetCurrent(Players.Current);
        }


        public void SetFirst(GamePlayer p)
        {
            Players.First = p;
            StateChanged();
        }

        public void SetCurrent(GamePlayer p)
        {
            Players.Current = p;
            if (!Players.Current.IsActive)
                throw new InvalidOperationException();
            StateChanged();
        }

        public void Do(HoldemAction action)
        {
//            _log.Info("preACT " + action + " State " + ToString());

            _history.Add(action);
            Layers.MyLogger.WriteLine(action.ToString());
            action.Do(this);
            _step++;

            if (null != _postAction)
                _postAction(this, new HoldemActionEventArgs(action, this));
            // to history
            StateChanged();
        }

        public override string ToString()
        {
            return GameID;
        }

        public string GameID { get { return _ID; } }


        public virtual void StageChanged(int old)
        {
            foreach (GamePlayer p in Players)
                p.OnStageChanged();
        }
        
        public virtual void StateChanged()
        {
            if (_stateChanged != null)
                _stateChanged(this, new EventArgs());
        }
    }


   

 
 
}